pepperstad.Map = function (opts) {

    this.game = opts.game;
    /**
     * Modes:
     * - pan
     * - drawStructurePoly
     * - editStructure
     * - deleteStructure
     */
    this.mode = "pan";
    this.paper = opts.paper;
    this.structureService = opts.structureService;
    this.resourceLoader = opts.resourceLoader;

    var editor = opts.editor;

    var config = pepperstad.config,
        storyConfig,
        boundaryX,
        boundaryY,
        iLayerX = 0,
        iLayerY = 0;

    var gui = this.game.gui;
    var self = this;

    this.init = function () {
        storyConfig = this.resourceLoader.get("story.config");
        boundaryX = storyConfig.imageWidth - config.playgroundWidth;
        boundaryY = storyConfig.imageHeight - config.playgroundHeight;
        this.initEventHandlers();
        this.center();
    };
    this.center = function () {
        this.moveTo(-Math.floor(storyConfig.imageWidth / 4), -Math.floor(storyConfig.imageHeight / 4));
    };
    this.moveTo = function (x, y) {
        iLayerX = x;
        iLayerY = y;
        this.updateLayerPositions();
    };
    this.initEventHandlers = function () {
        var layer = $("#playground"),
            bDragged = false,
            bMouseDown = false,
            iPrevMouseX = 0,
            iPrevMouseY = 0;

        // prevent chrome text cursor on drag
        // [ http://bugs.jqueryui.com/ticket/4163 ]
        layer.bind("selectstart", function () {
            return false;
        });
        layer.bind("mousedown", function (evt) {
            if (self.mode === "pan") {
                bMouseDown = true;
                layer.css("cursor", "move");
                iPrevMouseX = evt.pageX;
                iPrevMouseY = evt.pageY;
            }
        });
        layer.bind("click", function (evt) {
            var coord = new pepperstad.Coord({
                x: evt.pageX - iLayerX,
                y: evt.pageY - iLayerY
            });
            if (self.mode === "drawStructurePoly") {
                var struct = editor.currentStructure;
                struct.addPolyPoint(coord);
            }
        });
        layer.bind("mouseup", function () {
            if (self.mode === "pan") {
                if (!bDragged) {
                    self.structureService.highlight(null);
                    gui.closeBuildingInfo();
                }
                layer.css("cursor", "default");
            }
            onMouseUp();
        });
        // stop map panning if released outside viewport
        $(document).bind("mouseup", onMouseUp);

        layer.bind("mousemove", function (evt) {
            if (bMouseDown) {
                iLayerX = (iLayerX + (evt.pageX - iPrevMouseX));
                if (iLayerX < -boundaryX) iLayerX = -boundaryX;
                else if (iLayerX > 0) iLayerX = 0;
                iLayerY = (iLayerY + (evt.pageY - iPrevMouseY));
                if (iLayerY < -boundaryY) iLayerY = -boundaryY;
                else if (iLayerY > 0) iLayerY = 0;
                self.updateLayerPositions();

                if (iPrevMouseX != evt.pageX || iPrevMouseY != evt.pageY) {
                    bDragged = true;
                }
                iPrevMouseX = evt.pageX;
                iPrevMouseY = evt.pageY;
            }
        });

        function onMouseUp() {
            bMouseDown = false;
            bDragged = false;
        }

    };

    this.updateLayerPositions = function () {
        $("#background1").css("background-position",
                iLayerX + "px " + iLayerY + "px");
        $("#structures").css("top", (iLayerY - config.layerOffsetY) + "px")
            .css("left", (iLayerX - config.layerOffsetX) + "px");
    };

    this.handleStructureClicked = function (struct) {
        var reset = true;
        switch (self.mode) {
            case "editStructure":
                gui.showStructureEditor(struct,
                    editor.saveOrEditStructureHandler(struct, false));
                reset = false;
                break;
            case "deleteStructure":
                self.structureService.deleteStructure(struct);
                break;
            case "pan":
                self.structureService.highlight(struct);
                gui.showBuildingInfo(struct);
                break;
        }
        if (reset) {
            self.mode = "pan";
            gui.setAllButtonsActive(true);
            if (editor) {
                gui.setButtonActive("saveStructureButton", false);
            }
        }
    };
};

pepperstad.Coord = function (opts) {
    opts = opts || {};
    _.defaults(opts, {
        x: -1,
        y: -1
    });
    _.extend(this, opts);
};
